package cn.ys.user.service.impl;

import cn.ys.base.cons.RegisterCons;
import cn.ys.base.cons.WechatCons;
import cn.ys.base.jwt.JwtUtils;
import cn.ys.base.jwt.RsaUtils;
import cn.ys.base.jwt.UserInfo;
import cn.ys.base.util.AjaxResult;
import cn.ys.base.util.BussinessException;
import cn.ys.base.util.HttpUtil;
import cn.ys.base.util.MD5Utils;
import cn.ys.org.dto.BinderDto;
import cn.ys.org.dto.LoginDto;
import cn.ys.org.dto.WechatDto;
import cn.ys.system.domain.Menu;
import cn.ys.system.mapper.MenuMapper;
import cn.ys.system.mapper.PermissionMapper;
import cn.ys.user.domain.Logininfo;
import cn.ys.user.domain.User;
import cn.ys.user.domain.Wxuser;
import cn.ys.user.mapper.LogininfoMapper;
import cn.ys.user.mapper.UserMapper;
import cn.ys.user.mapper.WxuserMapper;
import cn.ys.user.service.LoginService;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.Get;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;

import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private LogininfoMapper loginMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxuserMapper wxuserMapper;

    @Autowired
    private UserMapper userMapper;

    @Value("${jwt.pri}")
    private String pri;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private MenuMapper menuMapper;

    // 账号密码登录
    @Override
    public AjaxResult account(LoginDto dto) {
        // 1，校验参数 dto已做
        // 2.根据账号查询密码是否存在
        Logininfo logininfo = loginMapper.findByaccount(dto);
        if(logininfo == null) {
            throw new BussinessException("账户或密码错误");
        }
        // 3.判断密码是否正确
        String dtoPassword = logininfo.getPassword();
        String password = MD5Utils.encrypByMd5(logininfo.getSalt() + dto.getPassword());
        if(!password.equals(dtoPassword)){
            throw new BussinessException("账户或密码错误");
        }

        Map<String, Object> us = getMap(logininfo);
        return AjaxResult.me().success(us);
    }

//    private Map<String, Object> getMap(Logininfo logininfo) {
//        // 4.生成uuid就是token
//        String token = UUID.randomUUID().toString();
//        // 5.将token和logininfo作为k v 结构存放在redis中
//        redisTemplate.opsForValue().set(token, logininfo,30, TimeUnit.MINUTES);
//        // 6.清除用户私密信息
//        logininfo.setPassword(null);
//        logininfo.setPhone(null);
//        // 7.将token和login info传回前端
//        Map<String,Object> us = new HashMap<>();
//        us.put("token",token);
//        us.put("logininfo", logininfo);
//        return us;
//    }


    // jwt登录方案
    private Map<String, Object> getMap(Logininfo logininfo) {
        // 7.将token和login info传回前端
        Map<String,Object> us = new HashMap<>();
        PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource(pri).getFile());
        UserInfo userInfo = new UserInfo();
        userInfo.setLogininfo(logininfo);
        // 判断用户是否是后台人员
        if(0 == logininfo.getType()){
            // 根据后台人员id查询对应按钮权限
            List<String> snList = permissionMapper.findByLogininfoId(logininfo.getId());
            // 将获取到的数据添加到userinfo中
            userInfo.setPermissions(snList);
            // 根据id查询菜单权限
            List<Menu> menus = menuMapper.findByLogininfoId(logininfo.getId());
            // 将获取到的数据添加到userinfo中
            userInfo.setMenus(menus);
            // 将数据添加到返回前端数据中
            us.put("permissions", snList);
            us.put("menus", menus);
        }
        String token = JwtUtils.generateTokenExpireInMinutes(userInfo, privateKey, 3000);
        // 6.清除用户私密信息
        logininfo.setPassword(null);
        logininfo.setPhone(null);
        us.put("token",token);
        us.put("logininfo", logininfo);
        return us;
    }

    // 微信登录
    @Override
    public AjaxResult wechat(WechatDto dto) {
        // 1.校验参数 dto已做
        // 2.调用微信第二个接口，获取token和openId
        String jsonStr = HttpUtil.httpGet(String.format(WechatCons.SECOND_INTER, WechatCons.APPID, WechatCons.SECRET, dto.getCode()));
        if (jsonStr == null) {
            throw new BussinessException("哦豁，微信登录出现问题，请联系微信客服");
        }
        // 2.1将jsonStr转化为一个对象
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        String accessToken = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");
        // 3.通过openId查询wxuser中是否有数据
        Wxuser wxuser = wxuserMapper.findByOpenId(openid);
        // 3.1判断wxuser是否存在数据
        if(wxuser != null && wxuser.getUserId() != null){
            // 4.有数据跳转到登录
            // 登录需要token和logininfo
            Logininfo logininfo = loginMapper.findByUserId(wxuser.getUserId());
            Map<String,Object> result = getMap(logininfo);
            return AjaxResult.me().success(result);
        }
        // 5.没有数据跳转到前端绑定页面 ?accessToken="+accessToken+"&openId="+openId
        StringBuilder builder = new StringBuilder();
        builder.append("?accessToken=")
                .append(accessToken)
                .append("&openId=")
                .append(openid);
        return AjaxResult.me().fail("nobinder").setResultObj(builder.toString());
    }

    // 绑定
    @Override
    public AjaxResult binder(BinderDto dto) {
        // 1.校验参数
        // 2.判断手机验证码是否正确
        // 通过业务键加手机号在redis中取
        String verification  = (String) redisTemplate.opsForValue().get(String.format(RegisterCons.REGISTER_KEY, dto.getPhone()));
        // 判断是否正确及过期
        if(StringUtils.isBlank(verification) || !dto.getVerifyCode().equals(verification)){
            throw new BussinessException("手机验证码无效");
        }
        // 3.调用第三个接口
        String json = HttpUtil.httpGet(String.format(WechatCons.THIRD_INTER, dto.getAccessToken(), dto.getOpenId()));

        // 4.将json转换成对象
        Wxuser wxuser = JSONObject.parseObject(json, Wxuser.class);

        // 5.根据手机号查询user表
        User user = userMapper.findByPhone(dto.getPhone());
        Logininfo logininfo = new Logininfo();
        // 6.判断user中数据是否存在
        if (user == null){
            // 6.1如果为空添加三张表
            // 先添加logininfo
            user = dto.getUser();

            BeanUtils.copyProperties(user,logininfo);
            logininfo.setType(1);
            logininfo.setDisable(1);
            loginMapper.add(logininfo);
            user.setLogininfoId(logininfo.getId());
            // 添加user对象
            userMapper.add(user);
        }
        // 添加wxuser对象
        wxuser.setUserId(user.getId());
        wxuserMapper.add(wxuser);
        // 登录需要token和logininfo
        logininfo = loginMapper.findByUserId(wxuser.getUserId());
        Map<String,Object> result = getMap(logininfo);
        return AjaxResult.me().success(result);
    }
}
